function [lpostmin,xmax,exitflag,output,Hx]=...
    estima_fmincon(x0,parvec,parposest,funcmod,Y,trainvec,prpar,prss,solveopt,addsol,ssposest,estimopt)
% ======================================================================
% ESTIMA_FMINCON.M
%
% Uses FMINCON optimization routine 
% Function underlying minization is identical to LMJ_POSTOPTIM.m and is
% included as a nested function. Only difference is that the parameter does 
% not go through the transformation matrix since the bounds are directly applied to the optimization 
% procedure using BOUNDS loaded from prior. 
% Hence X0 is an unstransformed starting value 
% format.  
%
% Input 
% ------
% Note:     Input PRPAR.LBND and PRPAR.UBND is truncated inside code 
% ESTIMOPT  Has all the settings for the optimization  
% Output 
% ------
% XMIN      in MIN  space for compatibility with GENSYSOUTPUT 
% XMODEL    in MODEL space  
% LPOSTMIN  stil *(-1) 
% Using OUTPUT, will display end message in a DIARY file created in the
% output subdirectory 
% 
% Alejandro Justiniano  January 11 2008 
% 1/13/09 Added LBND and UBND in priordens s.t. can work with the truncated
% BETA 
% =======================================================================
clear x lpostd; 
if any(imag(x0)~=0);error('Initial guess X0 cannot be imaginary');end
% Truncate bounds 
% ========================================================================
% Define the bounds for the optimization to ensure compatibility with
% INDMAT. Also check suggested starting point is within bounds, else adjust
% BOUNDS should NOT be truncated 
% ========================================================================
offset=1e-8; 
bounds=[prpar.lbnd(parposest)+offset prpar.ubnd(parposest)-offset]; 
check1=find(x0 < bounds(:,1));
check2=find(x0 > bounds(:,2)); 
if ~isempty(check1) 
    check1_disc=abs(x0(check1)-prpar.lbnd(check1)); 
    if max(check1_disc) > 0.01;error('Starting value is below lower bound');end
    x0(check1)=x0(check1)+check1_disc+offset; 
end 
if ~isempty(check2) 
    check2_disc=abs(x0(check2)-prpar.ubnd(check2)); 
    if max(check2_disc) > 0.01;
        dispaj('Positions ',check2(:),' above upper bound')
        error('Starting value is above upper bound')
    end
    x0(check2)=x0(check2)-check2_disc-offset;
end 
clear check* offset; 
% ========================================================================
% Begin Optimization  
% ========================================================================
tic;
[xmax,lpostmin,exitflag,output,junk,gradx,Hx]=fmincon(@lmj_postoptimsub,x0,[],[],[],[],bounds(:,1),bounds(:,2),[],estimopt);
% ============================================
%           NESTED FUNCTION
% ============================================
    function lpostd=lmj_postoptimsub(x) 
        lpostd=1e20;
        parvec(parposest)=x;        
        [G1,impact,C,eu,SDX,ZZ,junk,ssvec]=feval(funcmod,parvec,solveopt,addsol);
        if isequal(eu,[1;1])==0;disp('Non existence or uniqueness');return;end
        
        [T,nn]=size(Y);
        if any(C~=0)==1;
            Ydem=(Y-repmat((ZZ*C)',[T 1]))';
        else
            Ydem=Y'; 
        end;
        MM=impact*(SDX');
        try
            pshat=disclyap_fast(G1,MM*(MM'));
            if ~isempty(find(isnan(pshat))~=0)
                disp('PSHAT contains Nan entries')
                return
            end
        catch
            disp('Warning! Problems with initialization in GENSYSPOST_VEC');
            return;
        end
        shat=zeros(size(G1,1),1);
        lht=zeros(T,1);
        try
            for ii=1:T;
                [shat,pshat,lht(ii)]=kf(Ydem(:,ii),ZZ,shat,pshat,G1,MM);
            end
        catch
            disp('Warning! Problems with Kalman filter in GENSYSPOST_FMINCON');
            lasterror
            return
        end
        lht=lht(trainvec(1):trainvec(2));
        %mLogL=-0.5*length(lht)*nn*log(2*pi)+sum(lht);
        % Avoid constant for optimization, numerical overflow/bad gradient 
        
        % 2. Prior for the parameters 
        % 3. Prior for the SS 
        if ~isempty(ssposest)
            lpriord_ss = sum(priordens(ssvec(ssposest), prss.prior, prss.alphap, prss.betap, prss.lbnd, prss.ubnd));
        else
            lpriord_ss=0;
        end
        lpriord=sum(priordens(parvec,prpar.prior,prpar.alphap,prpar.betap,prpar.lbnd,prpar.ubnd));
        if isinf(abs(lpriord))==1;disp('Prior is INF');return;end
        clear lpostd; 
        %lpostd=-(mLogL+lpriord);
        lpostd=-(lpriord+lpriord_ss+sum(lht)); 
        %disp(['LPOSTD=',num2str(lpostd)]); 
    end
end